import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class    GomokuGame extends JFrame {
    // 棋盘基础参数
    private static final int BOARD_SIZE = 15;  // 15x15标准棋盘
    private static final int CELL_SIZE = 40;   // 每个格子的像素大小
    private static final int MARGIN = 50;      // 棋盘边距

    // 游戏规则引擎
    private GobangRules gameRules;
    private boolean useForbiddenRules = true;  // 是否启用禁手规则

    // UI组件
    private final BoardPanel boardPanel;
    private final JLabel statusLabel;
    private JButton restartButton;




    public GomokuGame() {
        // 初始化游戏规则
        gameRules = new GobangRules(BOARD_SIZE, useForbiddenRules);

        // 初始化窗口基本属性
        setTitle("五子棋 - 禁手规则");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);  // 窗口居中显示

        // 初始化棋盘面板
        boardPanel = new BoardPanel();
        boardPanel.setBackground(new Color(238, 210, 172));  // 模拟木质棋盘颜色

        // 初始化状态标签
        statusLabel = new JLabel("黑方回合");
        statusLabel.setHorizontalAlignment(JLabel.CENTER);

        // 初始化重启按钮
        restartButton = new JButton("重新开始");
        restartButton.addActionListener(e -> restartGame());

        // 添加鼠标监听（落子逻辑）
        boardPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (gameRules.isGameOver()) return;  // 游戏结束后禁止操作

                // 清除之前的禁手标记
                boardPanel.clearForbiddenPosition();

                // 将鼠标坐标转换为棋盘行列（0-14）
                int col = (e.getX() - MARGIN + CELL_SIZE / 2) / CELL_SIZE;
                int row = (e.getY() - MARGIN + CELL_SIZE / 2) / CELL_SIZE;

                // 检查落子有效性并落子
                int forbiddenType = gameRules.makeMove(row, col);
                if (forbiddenType == GobangRules.FORBIDDEN_NONE) {
                    // 正常落子
                    boardPanel.repaint();  // 刷新棋盘显示
                    updateGameStatus();    // 更新游戏状态显示
                } else if (forbiddenType != GobangRules.FORBIDDEN_NONE) {
                    // 触发禁手，撤销落子
                    gameRules.undoMove(row, col);

                    // 标记禁手位置
                    boardPanel.setForbiddenPosition(row, col);

                    // 提示用户
                    String forbiddenMsg = GobangRules.getForbiddenTypeName(forbiddenType);
                    JOptionPane.showMessageDialog(
                            GomokuGame.this,
                            "禁手！" + forbiddenMsg + "，请重新选择位置。",
                            "非法操作",
                            JOptionPane.WARNING_MESSAGE
                    );
                }
            }
        });

        // 布局设置
        setLayout(new BorderLayout());
        add(boardPanel, BorderLayout.CENTER);

        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new FlowLayout());
        controlPanel.add(restartButton);
        controlPanel.add(statusLabel);
        add(controlPanel, BorderLayout.SOUTH);

        pack();  // 自动调整窗口大小
        setResizable(false);  // 禁止调整窗口大小
    }

    private void restartGame() {
        gameRules = new GobangRules(BOARD_SIZE, useForbiddenRules);
        boardPanel.repaint();
        updateGameStatus();
    }

    private void updateGameStatus() {
        if (gameRules.isGameOver()) {
            int winner = gameRules.getWinner();
            if (winner == GobangRules.BLACK) {
                statusLabel.setText("黑方胜利！");
                JOptionPane.showMessageDialog(this, "黑方胜利！", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
            } else if (winner == GobangRules.WHITE) {
                // 检查是否因禁手获胜
                String reason = gameRules.getLastForbiddenType() != GobangRules.FORBIDDEN_NONE
                        ? "（黑方触发" + GobangRules.getForbiddenTypeName(gameRules.getLastForbiddenType()) + "）"
                        : "";
                statusLabel.setText("白方胜利！" + reason);
                JOptionPane.showMessageDialog(this, "白方胜利！" + reason, "游戏结束", JOptionPane.INFORMATION_MESSAGE);
            } else {
                statusLabel.setText("平局！");
                JOptionPane.showMessageDialog(this, "平局！", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
            }
        } else {
            statusLabel.setText(gameRules.getCurrentPlayer() == GobangRules.BLACK ? "黑方回合" : "白方回合");
        }
    }

    // 棋盘面板（自定义绘制逻辑）
    private class BoardPanel extends JPanel {
        private int forbiddenX = -1;
        private int forbiddenY = -1;
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            drawBoardGrid(g);   // 绘制棋盘网格
            drawStarPoints(g);  // 绘制天元/星位
            drawPieces(g);      // 绘制棋子

            // 高亮禁手位置
            if (forbiddenX >= 0 && forbiddenY >= 0) {
                highlightForbiddenPosition(g, forbiddenX, forbiddenY);
            }
        }

        // 添加高亮禁手位置的方法
        private void highlightForbiddenPosition(Graphics g, int x, int y) {
            int px = MARGIN + y * CELL_SIZE;
            int py = MARGIN + x * CELL_SIZE;

            g.setColor(new Color(255, 0, 0, 100)); // 半透明红色
            g.fillOval(px - CELL_SIZE/2, py - CELL_SIZE/2,
                    CELL_SIZE, CELL_SIZE);
        }

        // 添加设置禁手位置的方法
        public void setForbiddenPosition(int x, int y) {
            forbiddenX = x;
            forbiddenY = y;
            repaint();
        }

        // 清除禁手位置标记
        public void clearForbiddenPosition() {
            forbiddenX = -1;
            forbiddenY = -1;
            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            // 计算棋盘总尺寸（边距+格子数*格子大小）
            return new Dimension(MARGIN*2 + BOARD_SIZE*CELL_SIZE,
                    MARGIN*2 + BOARD_SIZE*CELL_SIZE);
        }

        // 绘制棋盘网格线
        private void drawBoardGrid(Graphics g) {
            g.setColor(Color.BLACK);
            // 横线
            for (int i = 0; i < BOARD_SIZE; i++) {
                int y = MARGIN + i * CELL_SIZE;
                g.drawLine(MARGIN, y, MARGIN + (BOARD_SIZE-1)*CELL_SIZE, y);
            }
            // 竖线
            for (int i = 0; i < BOARD_SIZE; i++) {
                int x = MARGIN + i * CELL_SIZE;
                g.drawLine(x, MARGIN, x, MARGIN + (BOARD_SIZE-1)*CELL_SIZE);
            }
        }

        // 绘制天元和星位（中心点+四个角点）
        private void drawStarPoints(Graphics g) {
            int center = BOARD_SIZE / 2;  // 天元坐标（7,7）
            int[] starPositions = {center, center-3, center+3};  // 星位坐标偏移量

            for (int x : starPositions) {
                for (int y : starPositions) {
                    if ((x == center && y == center) ||  // 天元
                            (Math.abs(x - center) == 3 && Math.abs(y - center) == 3)) {  // 四角星位
                        int px = MARGIN + x * CELL_SIZE;
                        int py = MARGIN + y * CELL_SIZE;
                        g.fillOval(px - 3, py - 3, 6, 6);  // 绘制直径6px的黑点
                    }
                }
            }
        }

        // 绘制所有棋子
        private void drawPieces(Graphics g) {
            for (int row = 0; row < BOARD_SIZE; row++) {
                for (int col = 0; col < BOARD_SIZE; col++) {
                    int cell = gameRules.getCell(row, col);
                    if (cell != GobangRules.EMPTY) {
                        int x = MARGIN + col * CELL_SIZE;
                        int y = MARGIN + row * CELL_SIZE;
                        // 绘制棋子（黑棋实心，白棋带边框）
                        g.setColor(cell == GobangRules.BLACK ? Color.BLACK : Color.WHITE);
                        g.fillOval(x - CELL_SIZE/2 + 2, y - CELL_SIZE/2 + 2,
                                CELL_SIZE - 4, CELL_SIZE - 4);
                        if (cell == GobangRules.WHITE) {  // 白棋加黑边
                            g.setColor(Color.BLACK);
                            g.drawOval(x - CELL_SIZE/2 + 2, y - CELL_SIZE/2 + 2,
                                    CELL_SIZE - 4, CELL_SIZE - 4);
                        }
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        // 确保UI在事件调度线程中运行（Swing规范）
        SwingUtilities.invokeLater(() -> {
            new GomokuGame().setVisible(true);
        });
    }
}

// 完整的GobangRules类实现（包含禁手规则）
class GobangRules {
    public static final int EMPTY = 0;
    public static final int BLACK = 1;
    public static final int WHITE = 2;

    // 禁手类型
    public static final int FORBIDDEN_NONE = 0;
    public static final int FORBIDDEN_THREE_THREE = 1;
    public static final int FORBIDDEN_FOUR_FOUR = 2;
    public static final int FORBIDDEN_OVERLINE = 3;

    // 棋型类型
    private static final int NONE = 0;        // 无棋型
    private static final int OPEN_THREE = 1;  // 活三
    private static final int HALF_FOUR = 2;   // 冲四
    private static final int OPEN_FOUR = 3;   // 活四
    private static final int FIVE = 4;        // 五连
    private static final int OVERLINE = 5;    // 长连

    private int boardSize;
    private int[][] board;
    private int currentPlayer;
    private boolean gameOver;
    private int winner;
    private boolean useForbiddenRules;
    private int lastForbiddenType;  // 记录最后一次禁手类型

    public GobangRules(int boardSize, boolean useForbiddenRules) {
        this.boardSize = boardSize;
        this.board = new int[boardSize][boardSize];
        this.currentPlayer = BLACK;
        this.gameOver = false;
        this.winner = EMPTY;
        this.useForbiddenRules = useForbiddenRules;
        this.lastForbiddenType = FORBIDDEN_NONE;
        initializeBoard();
    }

    private void initializeBoard() {
        for (int i = 0; i < boardSize; i++) {
            for (int j = 0; j < boardSize; j++) {
                board[i][j] = EMPTY;
            }
        }
    }

    private boolean isValidMove(int x, int y) {
        return x >= 0 && x < boardSize && y >= 0 && y < boardSize && board[x][y] == EMPTY;
    }

    private boolean isBoardFull() {
        for (int i = 0; i < boardSize; i++) {
            for (int j = 0; j < boardSize; j++) {
                if (board[i][j] == EMPTY) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean checkWin(int x, int y, int player) {
        int[][] directions = {
                {1, 0}, {0, 1}, {1, 1}, {1, -1}
        };

        for (int[] dir : directions) {
            int count = 1;

            // 正方向检查
            for (int i = 1; i < 5; i++) {
                int nx = x + dir[0] * i;
                int ny = y + dir[1] * i;

                if (nx >= 0 && nx < boardSize && ny >= 0 && ny < boardSize &&
                        board[nx][ny] == player) {
                    count++;
                } else {
                    break;
                }
            }

            // 反方向检查
            for (int i = 1; i < 5; i++) {
                int nx = x - dir[0] * i;
                int ny = y - dir[1] * i;

                if (nx >= 0 && nx < boardSize && ny >= 0 && ny < boardSize &&
                        board[nx][ny] == player) {
                    count++;
                } else {
                    break;
                }
            }

            if (count >= 5) {
                return true;
            }
        }

        return false;
    }

    private int checkForbidden(int x, int y) {
        int openThreeCount = 0;
        int fourCount = 0;
        boolean overline = false;

        int[][] directions = {
                {1, 0}, {0, 1}, {1, 1}, {1, -1}
        };

        for (int[] dir : directions) {
            int pattern = analyzePattern(x, y, dir);

            switch (pattern) {
                case OPEN_THREE:
                    openThreeCount++;
                    break;
                case HALF_FOUR:
                case OPEN_FOUR:
                    fourCount++;
                    break;
                case OVERLINE:
                    overline = true;
                    break;
            }
        }

        if (overline) return FORBIDDEN_OVERLINE;
        if (openThreeCount >= 2) return FORBIDDEN_THREE_THREE;
        if (fourCount >= 2) return FORBIDDEN_FOUR_FOUR;

        return FORBIDDEN_NONE;
    }

    private int analyzePattern(int x, int y, int[] dir) {
        int dx = dir[0];
        int dy = dir[1];

        // 计算连珠数量
        int leftCount = countConsecutive(x, y, -dx, -dy);
        int rightCount = countConsecutive(x, y, dx, dy);
        int totalCount = leftCount + 1 + rightCount;

        // 判断长连
        if (totalCount > 5) return OVERLINE;
        if (totalCount < 3) return NONE;

        // 检查两端的空位
        boolean leftOpen = isEmpty(x - dx * (leftCount + 1), y - dy * (leftCount + 1));
        boolean rightOpen = isEmpty(x + dx * (rightCount + 1), y + dy * (rightCount + 1));

        // 判断棋型
        if (totalCount == 5) return FIVE;

        if (totalCount == 4) {
            if (leftOpen && rightOpen) return OPEN_FOUR;
            return HALF_FOUR;
        }

        if (totalCount == 3) {
            if (leftOpen && rightOpen) return OPEN_THREE;
        }

        return NONE;
    }

    private int countConsecutive(int x, int y, int dx, int dy) {
        int count = 0;
        for (int i = 1; i < 6; i++) {
            int nx = x + dx * i;
            int ny = y + dy * i;
            if (nx >= 0 && nx < boardSize && ny >= 0 && ny < boardSize &&
                    board[nx][ny] == BLACK) {
                count++;
            } else {
                break;
            }
        }
        return count;
    }

    private boolean isEmpty(int x, int y) {
        return x >= 0 && x < boardSize && y >= 0 && y < boardSize &&
                board[x][y] == EMPTY;
    }

    // Getters
    public int getBoardSize() {
        return boardSize;
    }

    public int getCell(int x, int y) {
        return board[x][y];
    }

    public int getCurrentPlayer() {
        return currentPlayer;
    }

    public boolean isGameOver() {
        return gameOver;
    }

    public int getWinner() {
        return winner;
    }

    public int getLastForbiddenType() {
        return lastForbiddenType;
    }

    // 新增获取禁手类型的方法
    public static String getForbiddenTypeName(int type) {
        switch (type) {
            case FORBIDDEN_THREE_THREE: return "三三禁手";
            case FORBIDDEN_FOUR_FOUR: return "四四禁手";
            case FORBIDDEN_OVERLINE: return "长连禁手";
            default: return "无禁手";
        }
    }
    // 新增：撤销最后一步落子
    public void undoMove(int x, int y) {
        board[x][y] = EMPTY;
        gameOver = false;
        winner = EMPTY;
        currentPlayer = BLACK; // 重置为黑方（因为只有黑方有禁手）
    }

    // 修改 makeMove 方法，使其在检测到禁手时返回禁手类型而不是直接结束游戏
    public int makeMove(int x, int y) {
        if (gameOver || !isValidMove(x, y)) {
            return FORBIDDEN_NONE; // 无效移动
        }

        board[x][y] = currentPlayer;

        if (currentPlayer == BLACK && useForbiddenRules) {
            int forbiddenType = checkForbidden(x, y);
            if (forbiddenType != FORBIDDEN_NONE) {
                lastForbiddenType = forbiddenType;
                return forbiddenType; // 返回禁手类型
            }
        }

        if (checkWin(x, y, currentPlayer)) {
            gameOver = true;
            winner = currentPlayer;
        } else if (isBoardFull()) {
            gameOver = true;
        } else {
            // 切换玩家
            currentPlayer = (currentPlayer == BLACK) ? WHITE : BLACK;
        }

        return FORBIDDEN_NONE; // 正常落子
    }
}